Simple Scattergram
First we are going to try to present this pattern for different tiers of universities (admission rate as well as debt)
# Remove PrivacySuppressed Records and transform Debt Median into a numeric value - we can also do this on the main sc df
sc$DEBT_MDN[is.na(sc$DEBT_MDN)] <- 0;
brewer.pal(n=10,"PuBuGn")
n too large, allowed maximum for palette PuBuGn is 9
Returning the palette you asked for with that many colors
[1] "#FFF7FB" "#ECE2F0" "#D0D1E6" "#A6BDDB" "#67A9CF" "#3690C0" "#02818A" "#016C59" "#014636"
ShortPuBuGn <- c("#D0D1E6","#A6BDDB","#67A9CF","#3690C0","#02818A")
m <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>%
ggplot(., aes(x=ADM_RATE, y=DEBT_MDN,color=uni_rank)) +
geom_point(pch=21) +
geom_smooth(color='navy', se = FALSE) +
scale_color_manual(values=ShortPuBuGn)+
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background= element_rect(fill="white")) +
scale_y_discrete(limits=c(0,10000,20000,30000), labels=c('0','10','20','30')) +
labs(x='Admissions Rate', y='Median Loan Amount per Student\n(thousands)',
title='Student Debt and Admissions Rate',
color='Selectivity')
Continuous limits supplied to discrete scale.
Did you mean `limits = factor(...)` or `scale_*_continuous()`?
m

This plot sets out to show the relationship between median loan amount in 2019 and the admissions rate. The trend shown here is that as the admissions rate goes up (i.e., as schools become less selective), so does median loan amount (at least until we go from less selective to not selective). Based on the scatterplot, it can also be seen that the variance goes up in terms of median student loan amount (although it can also be seen that this is partially due to the much larger number of schools in the less selective buckets).
This is somewhat interesting because more exclusive/selective schools are on average viewed as more ‘competitive’ and ‘prestigious’ (e.g., Harvard, Stanford, etc.); a great deal of existent literature has noted that such ‘prestigious’ schools often end up admitting more people from economically privileged backgrounds (outside of those admitted specifically for diversity), as ‘merit-based’ admissions often correlate with access to economic and financial resources, which allow for access to resources helpful for competence signalling, such as standardized test prep courses, sports and activities, etc; furthermore, such schools include more financial resources (as more prestigious schools produce alma maters with higher socioeconomic outcomes) and thus potentially can help more with financial aid and scholarships.
This is a data table showing the breakdown of the university ranks (as I chose to rank them). I will note that from the dt alone wwe are seeing a downward trend in the ‘Median Student Loans’ column.
This data table summarizes how we categorized our variable for university selectivity grouping (from the College Scorecard file). It describes the median student loans and the number of universities in each category as of 2019, as well as the Minimum Acceptance Rate, and the Maximum Acceptance Rate thresholds.
sc_dt %>% dplyr::mutate(Description=paste(`University Selectivity`, '\n',`Number of Universities`,'Universities'), sep ="\n") %>%
treemap(index="Description",
vSize="Number of Universities",
type="index",
fontsize.labels=c(12, 8),
palette = viridis(5),
border.col="white",
title = 'Universities and Selectivity')
the condition has length > 1 and only the first element will be used

The treemap above visualizes and summarizes the selectivity grouping label and university counts within each of the categorical selectivity groupings. As shown above, the vast majority of schools in our dataset were ‘not selective’ or ‘less selective’; however, many of our analyses focus on the smaller categories (particularly selective to highly selective/elite), because these categories have more within-group homogeneity and furthermore are more interesting to our focal questions.
Student Debt over Time
#Process the data
sc_time <- read_csv('2010_2019_student_debt.csv')
sc_time<- sc_time %>% subset(DEBT_MDN !='PrivacySuppressed') %>%
transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>%
dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN))
sum(sc_time$UGDS,na.rm=TRUE)
[1] 90801007
Below is an interactive line graph (2010-2019) which details the trends in student debt over the years.
Between 2010 and 2018, the median loan amount per student increased by 2000-4000+ USD (inflation-adjusted) - nationally, the median student loan amount increased by 19%. When one disaggregates universities by selectivity, we see the same overall trend over time (i.e., there is a fair amount of increase during the period in terms of average student loans that students leave with upon entering repayment); however, some selectivity groups increased more dramatically than others (e.g., ‘More Selective’ or schools with 20-30% acceptance rates appeared to increase greatly in terms of student debt principal between 2015 and 2017, but this amount declined a bit again in 2018) and different selectivity groups decreased in median student debt over time (less selective; selective schools seemed to decrease in median debt following 2014).
To look at how median student debt has changed either by only national average or to look at specific ‘selectivity’ buckets, one can simply click to remove the remaining lines in the plot.
The following is (instead) a bar graph with fewer ‘university selectivity’ buckets.
sc_time_df <- sc_time %>% group_by(`Year_Ending`) %>% mutate(`Average Annual Student Debt - National` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% ungroup() %>%
dplyr::mutate(uni_rank = case_when(
ADM_RATE < 0.2 ~ 'highly selective',
ADM_RATE < 0.5 ~ 'moderately selective',
TRUE ~ 'less/not at all selective')) %>%
mutate(uni_rank = factor(uni_rank, levels=c('less/not at all selective', 'moderately selective', 'highly selective'))) %>%
group_by(uni_rank,Year_Ending) %>%
mutate(`Average Annual Student Debt (by Selectivity)` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>%
ungroup() %>%
group_by(`Year_Ending`,`Average Annual Student Debt (by Selectivity)`,
uni_rank,`Average Annual Student Debt - National`) %>% summarize() %>%
merge(cf) %>%
mutate(`Adjusted Average Annual Student Debt` = `Average Annual Student Debt (by Selectivity)`/
CPIAUCSL) %>%
mutate(`Adjusted Average Annual Student Debt - Composite` = `Average Annual Student Debt - National`/
CPIAUCSL)
sc_df <- sc_time_df %>% group_by(`Average Annual Student Debt - National`,`Adjusted Average Annual Student Debt - Composite`,Year_Ending) %>% summarize() %>% mutate(uni_rank='national average') %>% mutate(`Adjusted Average Annual Student Debt`=`Adjusted Average Annual Student Debt - Composite`) %>% dplyr::mutate(`Average Annual Student Debt (by Selectivity)` = `Average Annual Student Debt - National`) %>% merge(cf) %>% select(Year_Ending,`Average Annual Student Debt (by Selectivity)`, uni_rank, `Average Annual Student Debt - National`, CPIAUCSL, `Adjusted Average Annual Student Debt`,`Adjusted Average Annual Student Debt - Composite`)
sc_time_df <- sc_time_df %>% rbind(sc_df) %>% mutate(uni_rank = factor(uni_rank, levels=c('national average','less/not at all selective', 'moderately selective', 'highly selective')))
fig1 <- sc_time_df %>% plot_ly(x = ~Year_Ending, y = ~`Adjusted Average Annual Student Debt`, type = 'bar',
color = ~uni_rank, alpha=0.8, hovertemplate = 'Average Debt/Student (USD): %{y} <extra></extra>',colors='Purples') %>%
layout(yaxis = list(
title = "Average Annual Student Debt per Student\n(Adjusted for Inflation)"))
fig1
Chloropleth showing average student debt (this is only 2019 but I have a filter at the beginning that will allow me to incorporate a slider for the year).
# Additions of States df from Tigris File
library(tigris)
states <- states(cb = TRUE)
# Can change to sc_time_year
sc_time_2019 <- sc_time %>% subset(Year_Ending = 2019) %>%
group_by(STABBR) %>% mutate(`Average Student Loans`=sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% group_by(STABBR,`Average Student Loans`) %>% summarize()
# States
states_2019 <- states %>%
inner_join(sc_time_2019, by=c(STUSPS='STABBR'))
library(leaflet.providers)
library(leaflet)
#used 'success' measures.
pal = colorFactor('Greens', domain = states_2019$`Average Student Loans`)
pop_pop <- paste("State:",states_2019$NAME,"<br/>",
"Average Student Loans","<br/>",
"of Schools Located in State:",paste('$',round(states_2019$`Average Student Loans`)))
library(htmlwidgets)
library(htmltools)
states_2019_title <- tags$p(tags$style('p{color:gray; font-size: 14px; family: serif}'),
tags$b('Average Debt By State (2019)'))
leaflet(states_2019) %>% addProviderTiles("CartoDB.Positron") %>%
addPolygons(fillColor = ~pal(states_2019$`Average Student Loans`),
color = "white",
weight = 0.5,
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
fillOpacity = 0.7,
bringToFront = TRUE,
),popup=pop_pop) %>% addLegend(position = "bottomleft", colors =c("#EDF8E9","#BAE4B3","#74C476","#31A354","#006D2C"),
labels = c(paste('$',round(min(states_2019$`Average Student Loans`)))," "," "," ",
paste('$',round(max(states_2019$`Average Student Loans`)))),
title = "Average Student Loans (Per Student)") %>%
leaflet::setView(-98.5795, 39.8282, zoom=3) %>% addControl(states_2019_title, position='topright')
?addLegend
brewer.pal(n = 8, name = "RdYlGn")
# last edit to sc_time_2019 in chunk above for chloropleth
sc_time_2019_selective <- sc_time_2019 %>% dplyr::rename(lat = LATITUDE) %>% dplyr::rename(long = LONGITUDE) %>%
dplyr::rename(state = STABBR) %>% filter(ADM_RATE < 0.3) %>%
dplyr::mutate(uni_rank = case_when(
ADM_RATE < 0.05 ~ 'elite',
ADM_RATE < 0.2 ~ 'highly selective',
TRUE ~ 'selective'))
sc_time_2019_selective <- sc_time_2019_selective %>% subset(DEBT_MDN !='PrivacySuppressed') %>%
transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>%
dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN))
pal1 = colorFactor(ShortPuBuGn, domain = sc_time_2019_selective$`uni_rank`,reverse=TRUE)
#set popups
content <- paste("School",sc_time_2019_selective$INSTNM,"<br/>",
"Number of Undergrads:",sc_time_2019_selective$UGDS,"<br/>",
"Selectivity:", sc_time_2019_selective$uni_rank,"<br/>",
"Median Debt:",paste('$',round(sc_time_2019_selective$DEBT_MDN,2)),"<br/>")
sc_time_2019_selective
leaflet(sc_time_2019_selective) %>% addTiles('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png') %>%
addCircles(col = ~pal1(sc_time_2019_selective$uni_rank),
radius = ~DEBT_MDN,
popup = content,
fillOpacity = 0.7) %>%
leaflet::addLegend(position = "bottomleft",pal = pal1, values = sc_time_2019_selective$uni_rank,
title = "Average Student Loans (Per Student)")
?addLegend
setwd('~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd/')
sc_time <- read_csv('src/2010_2019_student_debt.csv')
sc_time
setwd("~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd")
sc_time <- read_csv('src/2010_2019_student_debt.csv')
sc_time<- sc_time %>% subset(DEBT_MDN !='PrivacySuppressed') %>%
transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>%
dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN)) %>%
mutate(DEBT_MDN_STUDENT = DEBT_MDN*UGDS)
sc_time
library(reshape2)
library(shiny)
ui <- fluidPage(
titlePanel("I love Graphs about Student Debt"),
# selectInput('year',
# 'Year',
# choices=c(2010,2011,2012,2013,2014,2015,2016,2017,2018,2019)),
sliderInput(inputId = "year",
label = "Year",
value = c(2010,2011,2012,2013,2014,2015,2016,2017,2018,2019)),
leafletOutput("studentdebtmap")
)
server <- function(input, output, session){
# Render plot of top 10 most popular names
sc_time_selective <- reactive({sc_time %>% subset(Year_Ending == input$year) %>%
group_by(STABBR) %>% mutate(`Average Student Loans`=sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>%
group_by(STABBR,`Average Student Loans`) %>% summarize()})
library(tigris)
states <- states(cb = TRUE)
states_year <- reactive({states %>% inner_join(sc_time_selective(), by=c(STUSPS='STABBR'))})
output$studentdebtmap <- renderLeaflet({
pal = colorFactor('Greens', domain = states_year()$`Average Student Loans`)
pop_pop <- paste("State:",states_year()$NAME,"<br/>",
"Average Student Loans","<br/>", "of Schools Located in State:",
paste('$',round(states_year()$`Average Student Loans`)))
sc_time_selective_title <- tags$p(tags$style('p{color:gray; font-size: 14px; family: serif}'),
tags$b('Average Debt By State (2019)'))
leaflet(states_year()) %>% addProviderTiles("CartoDB.Positron") %>%
addPolygons(fillColor = ~pal(states_year()$`Average Student Loans`),
color = "white",
weight = 0.5,
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
fillOpacity = 0.7,
bringToFront = TRUE,
),popup=pop_pop) %>% addLegend(position = "bottomleft", colors =c("#EDF8E9","#BAE4B3","#74C476","#31A354","#006D2C"),
labels = c(paste('$',round(min(states_year()$`Average Student Loans`)))," "," "," ",
paste('$',round(max(states_year()$`Average Student Loans`)))),
title = "Average Student Loans (Per Student)") %>%
leaflet::setView(-98.5795, 39.8282, zoom=3) %>% addControl(sc_time_selective_title, position='topright')
})
observe({
leafletProxy("studentdebtmap", data = states_year())
})
}
shinyApp(ui = ui, server = server)
Not all schools have similar amounts of median student debt burden (i.e., upon the beginning of the repayment period). This map summarizes the median debt burden by the state that the school is located in. As shown in this plot, some states (including schools in Pennsylvania, Minnesota, Illinois, etc.) tend to have the highest average median debt burden between the schools within. These states do not necessarily house the most prestigious schools. One of the things we can see when disaggregating this way is that locationally there is a lot of diversity of the student loan burden (on average) given to students by schools when disaggregated at the state level (ranging from 4K to 18K USD in 2019) Note that we have also included the shiny interactivity component in which one can select the year on the slider to see the state-level debt median disaggregation across the years; this is not the primary function but instead is a functionality we added to allow individuals to ‘explore the data’ a bit.
ui <- fluidPage(
titlePanel('The Cost of Higher Education: An Exploration of Student Debt in American Universities')
)
LS0tCnRpdGxlOiAiVmlzdWFsc19EcmFmdF8wNF8xNCIKYXV0aG9yOiAiQ29ubmllIFh1IgpkYXRlOiAiNC8xNC8yMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZC9zcmMvdmlzdWFscy8iKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCnNvdXJjZSgib3VydGhlbWUuUiIpCmBgYAoKYGBge3IgcGFja2FnZXMsIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KciA9IGdldE9wdGlvbigicmVwb3MiKQpyWyJDUkFOIl0gPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIKb3B0aW9ucyhyZXBvcyA9IHIpCiMgaW5zdGFsbC5wYWNrYWdlcyAoYmFzaWMpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKQoKIyBpbnN0YWxsLnBhY2thZ2VzIChyZWFkaW5nKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoWE1MKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KFJDdXJsKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJlYWRyKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KCJyZWFkeGwiKSkKCiMgaW5zdGFsbC5wYWNrYWdlcyAodGhlbWVzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2d0aGVtZXMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dyZXBlbCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShSQ29sb3JCcmV3ZXIpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodmlyaWRpcykpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShocmJydGhlbWVzKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSkpCgoKIyBpbnN0YWxsLnBhY2thZ2VzIChtYXBzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoUmdvb2dsZU1hcHMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dtYXApKQpzdXBwcmVzc01lc3NhZ2VzKGluc3RhbGwucGFja2FnZXMoIm1hcHMiKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCJ0bWFwIikpICMgaW5zdGFsbCB0aGUgQ1JBTiB2ZXJzaW9uCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0bWFwKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCdyZ2VvcycpKQoKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGRldnRvb2xzKSkKIyBMZXQncyBpbnN0YWxsIHRoZSBkZXZlbG9wbWVudCB2ZXJzaW9uIGZyb20gR2l0aHViLiBSdW4KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyc3R1ZGlvL2xlYWZsZXQiKQpgYGAKCmBgYHtyIGltcG9ydCBnZW5lcmFsIGRhdGEsIGVjaG89VFJVRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFNldCB0aGUgV0QgYXMgR3JvdXBfR19IaWdoZXJFZCAKc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZCIpCgojIFdoaWxlIG91ciBpbml0aWFsIENvbGxlZ2UgU2NvcmVjYXJkIG9ubHkgaW5jbHVkZWQgMjAxOSBpbml0aWFsbHksIEkgd2FzIGFibGUgdG8gcnVuIGEgc2ltcGxlIHB5dGhvbiBzY3JpcHQgdG8gY29uY2F0ZW5hdGUgYW5kIHNlbGVjdCBhIHNtYWxsIG51bWJlciBvZiByZWxldmFudCBjb2x1bW5zIGZvciBvdXIgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMuIFRodXMsIGFzIG91ciBmaXJzdCB2aXN1YWxpemF0aW9ucyBvbmx5IHVuY2x1ZGUgMjAxOSwgdGhlIGNvZGUgYmVsb3cgaXMgZm9yIHJlLWZpbHRlcmluZyB0aGUgY29uY2F0ZW5hdGVkIDIwMTAtMjAxOSBkYXRhIGJhY2sgaW50byBzaW1wbHkgMjAxOS4gCgpzY190aW1lIDwtIHJlYWQuY3N2KCcvc3JjLzIwMTBfMjAxOV9zdHVkZW50X2RlYnQuY3N2JykgCnNjIDwtIHNjX3RpbWUgJT4lIGZpbHRlcihZZWFyX0VuZGluZyA9PSAyMDE5KQpzY190aW1lCmxpYnJhcnkoZWR1Y2F0aW9uZGF0YSkKIyBUZXN0IFJ1biB3aXRoIHVzaW5nIGdldF9lZHVjYXRpb25fZGF0YSAKIyBkYXRhIDwtIGdldF9lZHVjYXRpb25fZGF0YShsZXZlbCA9ICJjb2xsZWdlLXVuaXZlcnNpdHkiLAojICAgICBzb3VyY2UgPSAiaXBlZHMiLAojICAgICB0b3BpYyA9ICJkaXJlY3RvcnkiLAojICAgICBmaWx0ZXJzID0gbGlzdCh5ZWFyID0gMjAxOSkpCiMgZGF0YQojIFNjb3JlY2FyZCBkYXRhIC0gMjAxOSAKCiMjIGNoYW5nZSBwcm9qZWN0aW9uIG9mIHNjIGRhdGEKc2MgPC0gc2MgJT4lCiAgZHBseXI6Om11dGF0ZSh1bmlfcmFuayA9IGNhc2Vfd2hlbigKICAgIEFETV9SQVRFIDwgMC4yIH4gJ2hpZ2hseSBzZWxlY3RpdmUvZWxpdGUnLAogICAgQURNX1JBVEUgPCAwLjMgfiAnbW9yZSBzZWxlY3RpdmUnLAogICAgQURNX1JBVEUgPCAwLjUgfiAnc2VsZWN0aXZlJywKICAgIEFETV9SQVRFIDwgMC43IH4gJ2xlc3Mgc2VsZWN0aXZlJywKICAgIFRSVUUgfiAnbm90IHNlbGVjdGl2ZScpKSAlPiUgbXV0YXRlKHVuaV9yYW5rID0gZmFjdG9yKHVuaV9yYW5rLCBsZXZlbHM9Yygnbm90IHNlbGVjdGl2ZScsICdsZXNzIHNlbGVjdGl2ZScsICdzZWxlY3RpdmUnLCAnbW9yZSBzZWxlY3RpdmUnLCAnaGlnaGx5IHNlbGVjdGl2ZS9lbGl0ZScpKSkKYGBgCgojIyBTaW1wbGUgU2NhdHRlcmdyYW0gCgpGaXJzdCB3ZSBhcmUgZ29pbmcgdG8gdHJ5IHRvIHByZXNlbnQgdGhpcyBwYXR0ZXJuIGZvciBkaWZmZXJlbnQgdGllcnMgb2YgdW5pdmVyc2l0aWVzIChhZG1pc3Npb24gcmF0ZSBhcyB3ZWxsIGFzIGRlYnQpCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KIyBSZW1vdmUgUHJpdmFjeVN1cHByZXNzZWQgUmVjb3JkcyBhbmQgdHJhbnNmb3JtIERlYnQgTWVkaWFuIGludG8gYSBudW1lcmljIHZhbHVlIC0gd2UgY2FuIGFsc28gZG8gdGhpcyBvbiB0aGUgbWFpbiBzYyBkZgpzYyRERUJUX01ETltpcy5uYShzYyRERUJUX01ETildIDwtIDA7CgpicmV3ZXIucGFsKG49MTAsIlB1QnVHbiIpClNob3J0UHVCdUduIDwtIGMoIiNEMEQxRTYiLCIjQTZCRERCIiwiIzY3QTlDRiIsIiMzNjkwQzAiLCIjMDI4MThBIikKCm0gPC0gc2MgJT4lIHN1YnNldChERUJUX01ETiAhPSdQcml2YWN5U3VwcHJlc3NlZCcpICU+JSB0cmFuc2Zvcm0oREVCVF9NRE4gPSBhcy5udW1lcmljKERFQlRfTUROKSkgJT4lIAogICAgICAgICAgICAgIGdncGxvdCguLCBhZXMoeD1BRE1fUkFURSwgeT1ERUJUX01ETixjb2xvcj11bmlfcmFuaykpICsKICBnZW9tX3BvaW50KHBjaD0yMSkgKwogIGdlb21fc21vb3RoKGNvbG9yPSduYXZ5Jywgc2UgPSBGQUxTRSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9U2hvcnRQdUJ1R24pKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSkgKwogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzPWMoMCwxMDAwMCwyMDAwMCwzMDAwMCksIGxhYmVscz1jKCcwJywnMTAnLCcyMCcsJzMwJykpICsKICBsYWJzKHg9J0FkbWlzc2lvbnMgUmF0ZScsIHk9J01lZGlhbiBMb2FuIEFtb3VudCBwZXIgU3R1ZGVudFxuKHRob3VzYW5kcyknLCAKICAgICAgIHRpdGxlPSdTdHVkZW50IERlYnQgYW5kIEFkbWlzc2lvbnMgUmF0ZScsCiAgICAgICBjb2xvcj0nU2VsZWN0aXZpdHknKQptCmBgYAogIAogIFRoaXMgcGxvdCBzZXRzIG91dCB0byBzaG93IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtZWRpYW4gbG9hbiBhbW91bnQgaW4gMjAxOSBhbmQgdGhlIGFkbWlzc2lvbnMgcmF0ZS4gVGhlIHRyZW5kIHNob3duIGhlcmUgaXMgdGhhdCBhcyB0aGUgYWRtaXNzaW9ucyByYXRlIGdvZXMgdXAgKGkuZS4sIGFzIHNjaG9vbHMgYmVjb21lIGxlc3Mgc2VsZWN0aXZlKSwgc28gZG9lcyBtZWRpYW4gbG9hbiBhbW91bnQgKGF0IGxlYXN0IHVudGlsIHdlIGdvIGZyb20gbGVzcyBzZWxlY3RpdmUgdG8gbm90IHNlbGVjdGl2ZSkuIEJhc2VkIG9uIHRoZSBzY2F0dGVycGxvdCwgaXQgY2FuIGFsc28gYmUgc2VlbiB0aGF0IHRoZSB2YXJpYW5jZSBnb2VzIHVwIGluIHRlcm1zIG9mIG1lZGlhbiBzdHVkZW50IGxvYW4gYW1vdW50IChhbHRob3VnaCBpdCBjYW4gYWxzbyBiZSBzZWVuIHRoYXQgdGhpcyBpcyBwYXJ0aWFsbHkgZHVlIHRvIHRoZSBtdWNoIGxhcmdlciBudW1iZXIgb2Ygc2Nob29scyBpbiB0aGUgbGVzcyBzZWxlY3RpdmUgYnVja2V0cykuICAKICBUaGlzIGlzIHNvbWV3aGF0IGludGVyZXN0aW5nIGJlY2F1c2UgbW9yZSBleGNsdXNpdmUvc2VsZWN0aXZlIHNjaG9vbHMgYXJlIG9uIGF2ZXJhZ2Ugdmlld2VkIGFzIG1vcmUgJ2NvbXBldGl0aXZlJyBhbmQgJ3ByZXN0aWdpb3VzJyAoZS5nLiwgSGFydmFyZCwgU3RhbmZvcmQsIGV0Yy4pOyBhIGdyZWF0IGRlYWwgb2YgZXhpc3RlbnQgbGl0ZXJhdHVyZSBoYXMgbm90ZWQgdGhhdCBzdWNoICdwcmVzdGlnaW91cycgc2Nob29scyBvZnRlbiBlbmQgdXAgYWRtaXR0aW5nIG1vcmUgcGVvcGxlIGZyb20gZWNvbm9taWNhbGx5IHByaXZpbGVnZWQgYmFja2dyb3VuZHMgKG91dHNpZGUgb2YgdGhvc2UgYWRtaXR0ZWQgc3BlY2lmaWNhbGx5IGZvciBkaXZlcnNpdHkpLCBhcyAnbWVyaXQtYmFzZWQnIGFkbWlzc2lvbnMgb2Z0ZW4gY29ycmVsYXRlIHdpdGggYWNjZXNzIHRvIGVjb25vbWljIGFuZCBmaW5hbmNpYWwgcmVzb3VyY2VzLCB3aGljaCBhbGxvdyBmb3IgYWNjZXNzIHRvIHJlc291cmNlcyBoZWxwZnVsIGZvciBjb21wZXRlbmNlIHNpZ25hbGxpbmcsIHN1Y2ggYXMgc3RhbmRhcmRpemVkIHRlc3QgcHJlcCBjb3Vyc2VzLCBzcG9ydHMgYW5kIGFjdGl2aXRpZXMsIGV0YzsgZnVydGhlcm1vcmUsIHN1Y2ggc2Nob29scyBpbmNsdWRlIG1vcmUgZmluYW5jaWFsIHJlc291cmNlcyAoYXMgbW9yZSBwcmVzdGlnaW91cyBzY2hvb2xzIHByb2R1Y2UgYWxtYSBtYXRlcnMgd2l0aCBoaWdoZXIgc29jaW9lY29ub21pYyBvdXRjb21lcykgYW5kIHRodXMgcG90ZW50aWFsbHkgY2FuIGhlbHAgbW9yZSB3aXRoIGZpbmFuY2lhbCBhaWQgYW5kIHNjaG9sYXJzaGlwcy4gCiAgClRoaXMgaXMgYSBkYXRhIHRhYmxlIHNob3dpbmcgdGhlIGJyZWFrZG93biBvZiB0aGUgdW5pdmVyc2l0eSByYW5rcyAoYXMgSSBjaG9zZSB0byByYW5rIHRoZW0pLiBJIHdpbGwgbm90ZSB0aGF0IGZyb20gdGhlIGR0IGFsb25lIHd3ZSBhcmUgc2VlaW5nIGEgZG93bndhcmQgdHJlbmQgaW4gdGhlICdNZWRpYW4gU3R1ZGVudCBMb2FucycgY29sdW1uLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENyZWF0ZSBEYXRhIFRhYmxlIChTdW1tYXJpemVkKSBmb3IgCmxpYnJhcnkoJ3NjYWxlcycpCgpzY19kdCA8LSBzYyAlPiUgc3Vic2V0KERFQlRfTUROICE9J1ByaXZhY3lTdXBwcmVzc2VkJykgJT4lIHRyYW5zZm9ybShERUJUX01ETiA9IGFzLm51bWVyaWMoREVCVF9NRE4pKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE51bWJlciBvZiBVbml2ZXJzaXRpZXNgID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSBtdXRhdGUoREVCVF9NRE5fU1RVREVOVFMgPSBERUJUX01ETipVR0RTKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE1lZGlhbiBTdHVkZW50IExvYW5zYCA9IHBhc3RlKCckJyxyb3VuZChzdW0oREVCVF9NRE5fU1RVREVOVFMsIG5hLnJtPVRSVUUpL3N1bShVR0RTLCBuYS5ybT1UUlVFKSwyKSkpICU+JSAKICBtdXRhdGUoYE1pbiBBY2NlcHRhbmNlIFJhdGVgID0gcGVyY2VudChtaW4oQURNX1JBVEUpKSkgJT4lIG11dGF0ZShgTWF4IEFjY2VwdGFuY2UgUmF0ZWAgPSBwZXJjZW50KG1heChBRE1fUkFURSkpKSAlPiUgdW5ncm91cCgpICU+JSAKICBncm91cF9ieSh1bmlfcmFuayxgTWVkaWFuIFN0dWRlbnQgTG9hbnNgLGBOdW1iZXIgb2YgVW5pdmVyc2l0aWVzYCxgTWluIEFjY2VwdGFuY2UgUmF0ZWAsYE1heCBBY2NlcHRhbmNlIFJhdGVgKSAlPiUgCiAgc3VtbWFyaXplKCkgJT4lIGRwbHlyOjpyZW5hbWUoYFVuaXZlcnNpdHkgU2VsZWN0aXZpdHlgID0gdW5pX3JhbmspCgppbnN0YWxsLnBhY2thZ2VzKCdEVCcpCmxpYnJhcnkoRFQpCnRhYmxlIDwtIGRhdGF0YWJsZShzY19kdCxzdHlsZSA9ICJkZWZhdWx0IixmaWx0ZXIgPSAndG9wJywgIGNhcHRpb24gPSAnVW5pdmVyc2l0aWVzIGFuZCBTZWxlY3Rpdml0eScpCnRhYmxlCgpgYGAKVGhpcyBkYXRhIHRhYmxlIHN1bW1hcml6ZXMgaG93IHdlIGNhdGVnb3JpemVkIG91ciB2YXJpYWJsZSBmb3IgdW5pdmVyc2l0eSBzZWxlY3Rpdml0eSBncm91cGluZyAoZnJvbSB0aGUgQ29sbGVnZSBTY29yZWNhcmQgZmlsZSkuIEl0IGRlc2NyaWJlcyB0aGUgbWVkaWFuIHN0dWRlbnQgbG9hbnMgYW5kIHRoZSBudW1iZXIgb2YgdW5pdmVyc2l0aWVzIGluIGVhY2ggY2F0ZWdvcnkgYXMgb2YgMjAxOSwgYXMgd2VsbCBhcyB0aGUgTWluaW11bSBBY2NlcHRhbmNlIFJhdGUsIGFuZCB0aGUgTWF4aW11bSBBY2NlcHRhbmNlIFJhdGUgdGhyZXNob2xkcy4gCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygndHJlZW1hcCcpCmluc3RhbGwucGFja2FnZXMoJ2hpZ2hjaGFydGVyJykKbGlicmFyeShoaWdoY2hhcnRlcikKbGlicmFyeSh0cmVlbWFwKQoKc2NfZHQgJT4lIGRwbHlyOjptdXRhdGUoRGVzY3JpcHRpb249cGFzdGUoYFVuaXZlcnNpdHkgU2VsZWN0aXZpdHlgLCAnXG4nLGBOdW1iZXIgb2YgVW5pdmVyc2l0aWVzYCwnVW5pdmVyc2l0aWVzJyksIHNlcCA9IlxuIikgJT4lCiAgdHJlZW1hcChpbmRleD0iRGVzY3JpcHRpb24iLAogICAgICAgICAgdlNpemU9Ik51bWJlciBvZiBVbml2ZXJzaXRpZXMiLAogICAgICAgIHR5cGU9ImluZGV4IiwKICAgICAgICBmb250c2l6ZS5sYWJlbHM9YygxMiwgOCksIAogICAgICAgIHBhbGV0dGUgPSAgdmlyaWRpcyg1KSwKICAgICAgICBib3JkZXIuY29sPSJ3aGl0ZSIsCiAgICAgICAgdGl0bGUgPSAnVW5pdmVyc2l0aWVzIGFuZCBTZWxlY3Rpdml0eScpCmBgYAoKICBUaGUgdHJlZW1hcCBhYm92ZSB2aXN1YWxpemVzIGFuZCBzdW1tYXJpemVzIHRoZSBzZWxlY3Rpdml0eSBncm91cGluZyBsYWJlbCBhbmQgdW5pdmVyc2l0eSBjb3VudHMgd2l0aGluIGVhY2ggb2YgdGhlIGNhdGVnb3JpY2FsIHNlbGVjdGl2aXR5IGdyb3VwaW5ncy4gQXMgc2hvd24gYWJvdmUsIHRoZSB2YXN0IG1ham9yaXR5IG9mIHNjaG9vbHMgaW4gb3VyIGRhdGFzZXQgd2VyZSAnbm90IHNlbGVjdGl2ZScgb3IgJ2xlc3Mgc2VsZWN0aXZlJzsgaG93ZXZlciwgbWFueSBvZiBvdXIgYW5hbHlzZXMgZm9jdXMgb24gdGhlIHNtYWxsZXIgY2F0ZWdvcmllcyAocGFydGljdWxhcmx5IHNlbGVjdGl2ZSB0byBoaWdobHkgc2VsZWN0aXZlL2VsaXRlKSwgYmVjYXVzZSB0aGVzZSBjYXRlZ29yaWVzIGhhdmUgbW9yZSB3aXRoaW4tZ3JvdXAgaG9tb2dlbmVpdHkgYW5kIGZ1cnRoZXJtb3JlIGFyZSBtb3JlIGludGVyZXN0aW5nIHRvIG91ciBmb2NhbCBxdWVzdGlvbnMuIAoKIyMgU2NhdHRlcmdyYW0gYXMgVmlvbGluIFBsb3QKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQptIDwtIHNjICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHg9dW5pX3JhbmssIHk9REVCVF9NRE4pKSArCiAgZ2VvbV92aW9saW4oYWVzKGZpbGw9dW5pX3JhbmssY29sb3I9dW5pX3JhbmspKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9U2hvcnRQdUJ1R24pICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1TaG9ydFB1QnVHbikgKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSkrCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHM9YygwLDEwMDAwLDIwMDAwLDMwMDAwKSwgbGFiZWxzPWMoJzAnLCcxMCcsJzIwJywnMzAnKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoJ25vdFxuc2VsZWN0aXZlXG4oPjcwJSknLCdsZXNzXG5zZWxlY3RpdmVcbig1MCUtNzAlKScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc2VsZWN0aXZlXG4oMzAlLTUwJSknLCdtb3JlXG5zZWxlY3RpdmVcbigyMCUtMzAlKScsJ2hpZ2hseVxuc2VsZWN0aXZlXG4oNSUtMjAlKScsJ2VsaXRlXG4oPDUlKScpKSArCgogIGxhYnMoeD0nU2VsZWN0aXZpdHlcbihhZG1pc3Npb24gcmF0ZSB0aHJlc2hvbGRzKScsIHk9J01lZGlhbiBMb2FuIEFtb3VudCBwZXIgU3R1ZGVudFxuKHRob3VzYW5kcyknLCAKICAgICAgIHRpdGxlPSdTZWxlY3RpdmUgU2Nob29scyBhbmQgU3R1ZGVudCBEZWJ0JywKICAgICAgIGNvbG9yPScnLGZpbGw9JycpCm0KYGBgClNob3dpbmcgdGhlIHByZXZpb3VzIHNjYXR0ZXJncmFtIHNwZWNpZmljYWxseSBhcyB2aW9saW4gcGxvdHMKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KaXBlZHMxNSA8LSBnZXRfZWR1Y2F0aW9uX2RhdGEobGV2ZWwgPSAiY29sbGVnZS11bml2ZXJzaXR5IiwKICAgIHNvdXJjZSA9ICJpcGVkcyIsCiAgICB0b3BpYyA9ICJncmFkLXJhdGVzLXBlbGwiLAogICAgZmlsdGVycyA9IGxpc3QoeWVhciA9IDIwMTUpKQppcGVkczE1CmBgYAoKCiMjIFN0dWRlbnQgRGVidCBvdmVyIFRpbWUKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KCiNQcm9jZXNzIHRoZSBkYXRhIApzY190aW1lIDwtIHJlYWRfY3N2KCcyMDEwXzIwMTlfc3R1ZGVudF9kZWJ0LmNzdicpIAoKc2NfdGltZTwtIHNjX3RpbWUgJT4lIHN1YnNldChERUJUX01ETiAhPSdQcml2YWN5U3VwcHJlc3NlZCcpICU+JSAKICB0cmFuc2Zvcm0oREVCVF9NRE4gPSBhcy5udW1lcmljKERFQlRfTUROKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoREVCVF9NRE4gPSBpZmVsc2UoaXMubmEoREVCVF9NRE4pLCAwLCBERUJUX01ETikpCgpgYGAKCgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CiNQcm9jZXNzIHRoZSBkYXRhIApzZXR3ZCgifi9Ecm9wYm94IChCdXNpbmVzcykvU3ByaW5nIDIwMjEvUU1TUyA1MDYzIC0gRGF0YSBWaXN1YWxpemF0aW9uIC9Hcm91cF9HX0hpZ2hlckVkIikKc2NfdGltZSA8LSByZWFkX2Nzdignc3JjLzIwMTBfMjAxOV9zdHVkZW50X2RlYnQuY3N2JykgCnNjX3RpbWU8LSBzY190aW1lICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAlPiUgCiAgbXV0YXRlKERFQlRfTUROX1NUVURFTlQgPSBERUJUX01ETipVR0RTKQpzY190aW1lCgpzdW0oc2NfdGltZSRVR0RTLG5hLnJtPVRSVUUpCmBgYAoKQmVsb3cgaXMgYW4gaW50ZXJhY3RpdmUgbGluZSBncmFwaCAoMjAxMC0yMDE5KSB3aGljaCBkZXRhaWxzIHRoZSB0cmVuZHMgaW4gc3R1ZGVudCBkZWJ0IG92ZXIgdGhlIHllYXJzLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENQSSBJbmZsYXRpb24gUmF0ZXMgLSBHb3QgQXZlcmFnZSBZZWFybHkgSW5mbGF0aW9uIFJhdGUgZm9yIFNjYWxpbmcgZm9yIFN0dWRlbnQgRGVidCAKaW5zdGFsbC5wYWNrYWdlcygncXVhbnRtb2QnKQpsaWJyYXJ5KHF1YW50bW9kKQpnZXRTeW1ib2xzKCJDUElBVUNTTCIsIHNyYz0nRlJFRCcpCmF2Zy5jcGkgPC0gYXBwbHkueWVhcmx5KENQSUFVQ1NMLCBtZWFuKQpjZiA8LSBhcy5kYXRhLmZyYW1lKGF2Zy5jcGkvYXMubnVtZXJpYyhhdmcuY3BpWycyMDA5J10pKSAKY2YkWWVhcl9FbmRpbmcgPC0gZm9ybWF0KGFzLkRhdGUocm93Lm5hbWVzKGNmKSwgZm9ybWF0PSIlWS0lbS0lZCIpLCIlWSIpCgojIE1lcmdlZCBmb3IgSW5mbGF0aW9uIApzY190aW1lX2RmIDwtIHNjX3RpbWUgJT4lIGdyb3VwX2J5KGBZZWFyX0VuZGluZ2ApICU+JSBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjIgfiAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuMyB+ICdtb3JlIHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNSB+ICdzZWxlY3RpdmUnLAogICAgQURNX1JBVEUgPCAwLjcgfiAnbGVzcyBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdub3Qgc2VsZWN0aXZlJykpICU+JQogIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25vdCBzZWxlY3RpdmUnLCAnbGVzcyBzZWxlY3RpdmUnLCAnc2VsZWN0aXZlJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lCiAgZ3JvdXBfYnkodW5pX3JhbmssWWVhcl9FbmRpbmcpICU+JSAKICBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShgWWVhcl9FbmRpbmdgLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsCiAgICAgICAgICAgdW5pX3JhbmssYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIHN1bW1hcml6ZSgpICU+JSAKICBtZXJnZShjZikgJT4lIAogIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAvCiAgICAgICAgICAgQ1BJQVVDU0wpICU+JSAKICBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLwogICAgICAgICAgIENQSUFVQ1NMKQoKc2NfZGYgPC0gc2NfdGltZV9kZiAlPiUgZ3JvdXBfYnkoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCxgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCxZZWFyX0VuZGluZykgJT4lIHN1bW1hcml6ZSgpICU+JSBtdXRhdGUodW5pX3Jhbms9J25hdGlvbmFsIGF2ZXJhZ2UnKSAlPiUgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgPWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgKSAlPiUgZHBseXI6Om11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIG1lcmdlKGNmKSAlPiUgc2VsZWN0KFllYXJfRW5kaW5nLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsIHVuaV9yYW5rLCBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLCBDUElBVUNTTCwgYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAsYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWApCnNjX3RpbWVfZGYgPC0gc2NfdGltZV9kZiAlPiUgcmJpbmQoc2NfZGYpICU+JSBtdXRhdGUodW5pX3JhbmsgPSBmYWN0b3IodW5pX3JhbmssIGxldmVscz1jKCduYXRpb25hbCBhdmVyYWdlJywnbm90IHNlbGVjdGl2ZScsICdsZXNzIHNlbGVjdGl2ZScsICdzZWxlY3RpdmUnLCAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lIAogIG11dGF0ZShgR3JvdXAgTGV2ZWxgID0gaWZlbHNlKHVuaV9yYW5rID09ICduYXRpb25hbCBhdmVyYWdlJywgJ05hdGlvbmFsJywnU2VsZWN0aXZpdHknKSkKc2NfZGYKc2NfdGltZV9kZgoKCnAgPC0gc2NfdGltZV9kZiAlPiUgCiAgZ2dwbG90KC4sYWVzKHg9WWVhcl9FbmRpbmcseT1gQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCwgY29sb3I9dW5pX3JhbmspKSArIAogIGdlb21fbGluZShhZXMobGluZXR5cGU9YEdyb3VwIExldmVsYCkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdncmV5JywiI0QwRDFFNiIsIiNBNkJEREIiLCIjNjdBOUNGIiwiIzM2OTBDMCIsIiMwMjgxOEEiKSkrCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcz1jKCJzb2xpZCIsICJkb3R0ZWQiKSkrCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmJhY2tncm91bmQ9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcShtaW4oc2NfdGltZSRZZWFyX0VuZGluZyksIG1heChzY190aW1lJFllYXJfRW5kaW5nKSwgYnkgPSAyKSwxKSkgKwogIGxhYnMoeD0nJywgeT0nSW5mbGF0aW9uLUFkanVzdGVkIE1lZGlhbiBMb2FuIEFtb3VudCBwZXIgU3R1ZGVudFxuKHRob3VzYW5kcyknLCAKICAgICAgIHRpdGxlPSdTdHVkZW50IERlYnQgSGFzIEJlZW4gUmlzaW5nIE92ZXIgVGhlIFllYXJzJywKICAgICAgIGNvbG9yPScnLGZpbGw9JycsZ3JvdXA9JycsbGluZXR5cGU9JycpCmdncGxvdGx5KHApCgoKYGBgCgogIEJldHdlZW4gMjAxMCBhbmQgMjAxOCwgdGhlIG1lZGlhbiBsb2FuIGFtb3VudCBwZXIgc3R1ZGVudCBpbmNyZWFzZWQgYnkgMjAwMC00MDAwKyBVU0QgKGluZmxhdGlvbi1hZGp1c3RlZCkgLSBuYXRpb25hbGx5LCB0aGUgbWVkaWFuIHN0dWRlbnQgbG9hbiBhbW91bnQgaW5jcmVhc2VkIGJ5IDE5JS4gV2hlbiBvbmUgZGlzYWdncmVnYXRlcyB1bml2ZXJzaXRpZXMgYnkgc2VsZWN0aXZpdHksIHdlIHNlZSB0aGUgc2FtZSAqb3ZlcmFsbCogdHJlbmQgb3ZlciB0aW1lIChpLmUuLCB0aGVyZSBpcyBhIGZhaXIgYW1vdW50IG9mIGluY3JlYXNlIGR1cmluZyB0aGUgcGVyaW9kIGluIHRlcm1zIG9mIGF2ZXJhZ2Ugc3R1ZGVudCBsb2FucyB0aGF0IHN0dWRlbnRzIGxlYXZlIHdpdGggdXBvbiBlbnRlcmluZyByZXBheW1lbnQpOyBob3dldmVyLCBzb21lIHNlbGVjdGl2aXR5IGdyb3VwcyBpbmNyZWFzZWQgbW9yZSBkcmFtYXRpY2FsbHkgdGhhbiBvdGhlcnMgKGUuZy4sICdNb3JlIFNlbGVjdGl2ZScgb3Igc2Nob29scyB3aXRoIDIwLTMwJSBhY2NlcHRhbmNlIHJhdGVzIGFwcGVhcmVkIHRvIGluY3JlYXNlIGdyZWF0bHkgaW4gdGVybXMgb2Ygc3R1ZGVudCBkZWJ0IHByaW5jaXBhbCBiZXR3ZWVuIDIwMTUgYW5kIDIwMTcsIGJ1dCB0aGlzIGFtb3VudCBkZWNsaW5lZCBhIGJpdCBhZ2FpbiBpbiAyMDE4KSBhbmQgZGlmZmVyZW50IHNlbGVjdGl2aXR5IGdyb3VwcyBkZWNyZWFzZWQgaW4gbWVkaWFuIHN0dWRlbnQgZGVidCBvdmVyIHRpbWUgKGxlc3Mgc2VsZWN0aXZlOyBzZWxlY3RpdmUgc2Nob29scyBzZWVtZWQgdG8gZGVjcmVhc2UgaW4gbWVkaWFuIGRlYnQgZm9sbG93aW5nIDIwMTQpLiAgCiAgVG8gbG9vayBhdCBob3cgbWVkaWFuIHN0dWRlbnQgZGVidCBoYXMgY2hhbmdlZCBlaXRoZXIgYnkgb25seSBuYXRpb25hbCBhdmVyYWdlIG9yIHRvIGxvb2sgYXQgc3BlY2lmaWMgJ3NlbGVjdGl2aXR5JyBidWNrZXRzLCBvbmUgY2FuIHNpbXBseSBjbGljayB0byByZW1vdmUgdGhlIHJlbWFpbmluZyBsaW5lcyBpbiB0aGUgcGxvdC4gCgpUaGUgZm9sbG93aW5nIGlzIChpbnN0ZWFkKSBhIGJhciBncmFwaCB3aXRoIGZld2VyICd1bml2ZXJzaXR5IHNlbGVjdGl2aXR5JyBidWNrZXRzLiAKYGBge3J9CnNjX3RpbWVfZGYgPC0gc2NfdGltZSAlPiUgZ3JvdXBfYnkoYFllYXJfRW5kaW5nYCkgJT4lIG11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgID0gc3VtKERFQlRfTUROX1NUVURFTlQsbmEucm09VFJVRSkvc3VtKFVHRFMsbmEucm09VFJVRSkpICU+JSB1bmdyb3VwKCkgJT4lIAogIGRwbHlyOjptdXRhdGUodW5pX3JhbmsgPSBjYXNlX3doZW4oCiAgICBBRE1fUkFURSA8IDAuMiB+ICdoaWdobHkgc2VsZWN0aXZlJywKICAgIEFETV9SQVRFIDwgMC41IH4gJ21vZGVyYXRlbHkgc2VsZWN0aXZlJywKICAgIFRSVUUgfiAnbGVzcy9ub3QgYXQgYWxsIHNlbGVjdGl2ZScpKSAlPiUKICBtdXRhdGUodW5pX3JhbmsgPSBmYWN0b3IodW5pX3JhbmssIGxldmVscz1jKCdsZXNzL25vdCBhdCBhbGwgc2VsZWN0aXZlJywgJ21vZGVyYXRlbHkgc2VsZWN0aXZlJywgJ2hpZ2hseSBzZWxlY3RpdmUnKSkpICU+JQogIGdyb3VwX2J5KHVuaV9yYW5rLFllYXJfRW5kaW5nKSAlPiUgCiAgbXV0YXRlKGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAgPSBzdW0oREVCVF9NRE5fU1RVREVOVCxuYS5ybT1UUlVFKS9zdW0oVUdEUyxuYS5ybT1UUlVFKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ3JvdXBfYnkoYFllYXJfRW5kaW5nYCxgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgLAogICAgICAgICAgIHVuaV9yYW5rLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGApICU+JSBzdW1tYXJpemUoKSAlPiUgCiAgbWVyZ2UoY2YpICU+JSAKICBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgLwogICAgICAgICAgIENQSUFVQ1NMKSAlPiUgCiAgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYC8KICAgICAgICAgICBDUElBVUNTTCkKCnNjX2RmIDwtIHNjX3RpbWVfZGYgJT4lIGdyb3VwX2J5KGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGAsYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWAsWWVhcl9FbmRpbmcpICU+JSBzdW1tYXJpemUoKSAlPiUgbXV0YXRlKHVuaV9yYW5rPSduYXRpb25hbCBhdmVyYWdlJykgJT4lIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YD1gQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCkgJT4lIGRwbHlyOjptdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGApICU+JSBtZXJnZShjZikgJT4lIHNlbGVjdChZZWFyX0VuZGluZyxgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgLCB1bmlfcmFuaywgYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCwgQ1BJQVVDU0wsIGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgLGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgKQpzY190aW1lX2RmIDwtIHNjX3RpbWVfZGYgJT4lIHJiaW5kKHNjX2RmKSAlPiUgbXV0YXRlKHVuaV9yYW5rID0gZmFjdG9yKHVuaV9yYW5rLCBsZXZlbHM9YygnbmF0aW9uYWwgYXZlcmFnZScsJ2xlc3Mvbm90IGF0IGFsbCBzZWxlY3RpdmUnLCAnbW9kZXJhdGVseSBzZWxlY3RpdmUnLCAnaGlnaGx5IHNlbGVjdGl2ZScpKSkgCgpmaWcxIDwtIHNjX3RpbWVfZGYgJT4lIHBsb3RfbHkoeCA9IH5ZZWFyX0VuZGluZywgeSA9IH5gQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCwgdHlwZSA9ICdiYXInLAogIGNvbG9yID0gfnVuaV9yYW5rLCBhbHBoYT0wLjgsIGhvdmVydGVtcGxhdGUgPSAnQXZlcmFnZSBEZWJ0L1N0dWRlbnQgKFVTRCk6ICV7eX0gPGV4dHJhPjwvZXh0cmE+Jyxjb2xvcnM9J1B1cnBsZXMnKSAlPiUgCiAgbGF5b3V0KHlheGlzID0gbGlzdCgKICB0aXRsZSA9ICJBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgcGVyIFN0dWRlbnRcbihBZGp1c3RlZCBmb3IgSW5mbGF0aW9uKSIpKQoKZmlnMQoKYGBgCgpDaGxvcm9wbGV0aCBzaG93aW5nIGF2ZXJhZ2Ugc3R1ZGVudCBkZWJ0ICh0aGlzIGlzIG9ubHkgMjAxOSBidXQgSSBoYXZlIGEgZmlsdGVyIGF0IHRoZSBiZWdpbm5pbmcgdGhhdCB3aWxsIGFsbG93IG1lIHRvIGluY29ycG9yYXRlIGEgc2xpZGVyIGZvciB0aGUgeWVhcikuCgpgYGB7ciBTdHVkZW50IERlYnQgbWFwIC0gQ2hsb3JvcGxldGgsIGVjaG89VFJVRSwgZXZhbD1UUlVFIH0KCiMgQWRkaXRpb25zIG9mIFN0YXRlcyBkZiBmcm9tIFRpZ3JpcyBGaWxlIApsaWJyYXJ5KHRpZ3JpcykKc3RhdGVzIDwtIHN0YXRlcyhjYiA9IFRSVUUpCgojIENhbiBjaGFuZ2UgdG8gc2NfdGltZV95ZWFyIApzY190aW1lXzIwMTkgPC0gc2NfdGltZSAlPiUgc3Vic2V0KFllYXJfRW5kaW5nID0gMjAxOSkgJT4lIAogIGdyb3VwX2J5KFNUQUJCUikgJT4lIG11dGF0ZShgQXZlcmFnZSBTdHVkZW50IExvYW5zYD1zdW0oREVCVF9NRE5fU1RVREVOVCxuYS5ybT1UUlVFKS9zdW0oVUdEUyxuYS5ybT1UUlVFKSkgJT4lIGdyb3VwX2J5KFNUQUJCUixgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkgJT4lIHN1bW1hcml6ZSgpCgojIFN0YXRlcyAKc3RhdGVzXzIwMTkgPC0gc3RhdGVzICU+JSAKICBpbm5lcl9qb2luKHNjX3RpbWVfMjAxOSwgYnk9YyhTVFVTUFM9J1NUQUJCUicpKSAKCgpsaWJyYXJ5KGxlYWZsZXQucHJvdmlkZXJzKQpsaWJyYXJ5KGxlYWZsZXQpCiN1c2VkICdzdWNjZXNzJyBtZWFzdXJlcy4gCgpwYWwgPSBjb2xvckZhY3RvcignR3JlZW5zJywgZG9tYWluID0gc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApCgpwb3BfcG9wIDwtIHBhc3RlKCJTdGF0ZToiLHN0YXRlc18yMDE5JE5BTUUsIjxici8+IiwKICAgICAgICAgICAgICAgICAiQXZlcmFnZSBTdHVkZW50IExvYW5zIiwiPGJyLz4iLAogICAgICAgICAgICAgICAgICJvZiBTY2hvb2xzIExvY2F0ZWQgaW4gU3RhdGU6IixwYXN0ZSgnJCcscm91bmQoc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSkKbGlicmFyeShodG1sd2lkZ2V0cykKbGlicmFyeShodG1sdG9vbHMpCnN0YXRlc18yMDE5X3RpdGxlIDwtIHRhZ3MkcCh0YWdzJHN0eWxlKCdwe2NvbG9yOmdyYXk7IGZvbnQtc2l6ZTogMTRweDsgZmFtaWx5OiBzZXJpZn0nKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZ3MkYignQXZlcmFnZSBEZWJ0IEJ5IFN0YXRlICgyMDE5KScpKQoKbGVhZmxldChzdGF0ZXNfMjAxOSkgJT4lIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKHN0YXRlc18yMDE5JGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSwKICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMC41LAogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LCAgCiAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygKICAgICAgICAgICAgICAgIHdlaWdodCA9IDUsCiAgICAgICAgICAgICAgICBjb2xvciA9ICIjNjY2IiwKICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LAogICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSwKICAgICAgICAgICAgICAgICkscG9wdXA9cG9wX3BvcCkgJT4lIGFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21sZWZ0IiwgY29sb3JzID1jKCIjRURGOEU5IiwiI0JBRTRCMyIsIiM3NEM0NzYiLCIjMzFBMzU0IiwiIzAwNkQyQyIpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhwYXN0ZSgnJCcscm91bmQobWluKHN0YXRlc18yMDE5JGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSkpLCIgIiwiICIsIiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgnJCcscm91bmQobWF4KHN0YXRlc18yMDE5JGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSkpKSwKICAgICAgICAgICAgdGl0bGUgPSAiQXZlcmFnZSBTdHVkZW50IExvYW5zIChQZXIgU3R1ZGVudCkiKSAlPiUKICBsZWFmbGV0OjpzZXRWaWV3KC05OC41Nzk1LCAzOS44MjgyLCB6b29tPTMpICU+JSBhZGRDb250cm9sKHN0YXRlc18yMDE5X3RpdGxlLCBwb3NpdGlvbj0ndG9wcmlnaHQnKQo/YWRkTGVnZW5kCmBgYAoKYGBge3J9CmJyZXdlci5wYWwobiA9IDgsIG5hbWUgPSAiUmRZbEduIikKYGBgCgpgYGB7ciBTdHVkZW50IERlYnQgTWFwIC0gcG9pbnRzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRSB9CiMgbGFzdCBlZGl0IHRvIHNjX3RpbWVfMjAxOSBpbiBjaHVuayBhYm92ZSBmb3IgY2hsb3JvcGxldGgKc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSA8LSBzY190aW1lXzIwMTkgJT4lIGRwbHlyOjpyZW5hbWUobGF0ID0gTEFUSVRVREUpICU+JSBkcGx5cjo6cmVuYW1lKGxvbmcgPSBMT05HSVRVREUpICU+JSAKICBkcGx5cjo6cmVuYW1lKHN0YXRlID0gU1RBQkJSKSAlPiUgZmlsdGVyKEFETV9SQVRFIDwgMC4zKSAlPiUgCiAgZHBseXI6Om11dGF0ZSh1bmlfcmFuayA9IGNhc2Vfd2hlbigKICAgIEFETV9SQVRFIDwgMC4wNSB+ICdlbGl0ZScsCiAgICBBRE1fUkFURSA8IDAuMiB+ICdoaWdobHkgc2VsZWN0aXZlJywKICAgIFRSVUUgfiAnc2VsZWN0aXZlJykpCnNjX3RpbWVfMjAxOV9zZWxlY3RpdmUgPC0gc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSAlPiUgc3Vic2V0KERFQlRfTUROICE9J1ByaXZhY3lTdXBwcmVzc2VkJykgJT4lIAogIHRyYW5zZm9ybShERUJUX01ETiA9IGFzLm51bWVyaWMoREVCVF9NRE4pKSAlPiUgCiAgZHBseXI6Om11dGF0ZShERUJUX01ETiA9IGlmZWxzZShpcy5uYShERUJUX01ETiksIDAsIERFQlRfTUROKSkgCgoKCnBhbDEgPSBjb2xvckZhY3RvcihTaG9ydFB1QnVHbiwgZG9tYWluID0gc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSRgdW5pX3JhbmtgLHJldmVyc2U9VFJVRSkKCiNzZXQgcG9wdXBzIApjb250ZW50IDwtIHBhc3RlKCJTY2hvb2wiLHNjX3RpbWVfMjAxOV9zZWxlY3RpdmUkSU5TVE5NLCI8YnIvPiIsCiAgICAgICAgICAgICAgICAgIk51bWJlciBvZiBVbmRlcmdyYWRzOiIsc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSRVR0RTLCI8YnIvPiIsCiAgICAgICAgICAgICAgICAgIlNlbGVjdGl2aXR5OiIsIHNjX3RpbWVfMjAxOV9zZWxlY3RpdmUkdW5pX3JhbmssIjxici8+IiwKICAgICAgICAgICAgICAgICAiTWVkaWFuIERlYnQ6IixwYXN0ZSgnJCcscm91bmQoc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSRERUJUX01ETiwyKSksIjxici8+IikKc2NfdGltZV8yMDE5X3NlbGVjdGl2ZQpsZWFmbGV0KHNjX3RpbWVfMjAxOV9zZWxlY3RpdmUpICU+JSBhZGRUaWxlcygnaHR0cDovL3tzfS5iYXNlbWFwcy5jYXJ0b2Nkbi5jb20vZGFya19hbGwve3p9L3t4fS97eX0ucG5nJykgJT4lCiAgYWRkQ2lyY2xlcyhjb2wgPSB+cGFsMShzY190aW1lXzIwMTlfc2VsZWN0aXZlJHVuaV9yYW5rKSwKICAgICAgICAgICAgIHJhZGl1cyA9IH5ERUJUX01ETiwKICAgICAgICAgICAgIHBvcHVwID0gY29udGVudCwKICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43KSAlPiUKICBsZWFmbGV0OjphZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tbGVmdCIscGFsID0gcGFsMSwgdmFsdWVzID0gc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSR1bmlfcmFuaywKICAgICAgICAgICAgdGl0bGUgPSAiQXZlcmFnZSBTdHVkZW50IExvYW5zIChQZXIgU3R1ZGVudCkiKQo/YWRkTGVnZW5kCmBgYApgYGB7cn0Kc2V0d2QoJ34vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZC8nKQpzY190aW1lIDwtIHJlYWRfY3N2KCdzcmMvMjAxMF8yMDE5X3N0dWRlbnRfZGVidC5jc3YnKSAKc2NfdGltZQpgYGAKCgpgYGB7cn0Kc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZCIpCnNjX3RpbWUgPC0gcmVhZF9jc3YoJ3NyYy8yMDEwXzIwMTlfc3R1ZGVudF9kZWJ0LmNzdicpIApzY190aW1lPC0gc2NfdGltZSAlPiUgc3Vic2V0KERFQlRfTUROICE9J1ByaXZhY3lTdXBwcmVzc2VkJykgJT4lIAogIHRyYW5zZm9ybShERUJUX01ETiA9IGFzLm51bWVyaWMoREVCVF9NRE4pKSAlPiUgCiAgZHBseXI6Om11dGF0ZShERUJUX01ETiA9IGlmZWxzZShpcy5uYShERUJUX01ETiksIDAsIERFQlRfTUROKSkgJT4lIAogIG11dGF0ZShERUJUX01ETl9TVFVERU5UID0gREVCVF9NRE4qVUdEUykKc2NfdGltZQoKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShzaGlueSkKdWkgPC0gZmx1aWRQYWdlKAogIHRpdGxlUGFuZWwoIkkgbG92ZSBHcmFwaHMgYWJvdXQgU3R1ZGVudCBEZWJ0IiksCiAgIyBzZWxlY3RJbnB1dCgneWVhcicsCiAgIyAnWWVhcicsCiAgIyBjaG9pY2VzPWMoMjAxMCwyMDExLDIwMTIsMjAxMywyMDE0LDIwMTUsMjAxNiwyMDE3LDIwMTgsMjAxOSkpLCAKICBzbGlkZXJJbnB1dChpbnB1dElkID0gInllYXIiLAogIGxhYmVsID0gIlllYXIiLAogIHZhbHVlID0gYygyMDEwLDIwMTEsMjAxMiwyMDEzLDIwMTQsMjAxNSwyMDE2LDIwMTcsMjAxOCwyMDE5KSksCiAgbGVhZmxldE91dHB1dCgic3R1ZGVudGRlYnRtYXAiKQoKKQoKc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQsIHNlc3Npb24pewogICMgUmVuZGVyIHBsb3Qgb2YgdG9wIDEwIG1vc3QgcG9wdWxhciBuYW1lcwogICAgc2NfdGltZV9zZWxlY3RpdmUgPC0gcmVhY3RpdmUoe3NjX3RpbWUgJT4lIHN1YnNldChZZWFyX0VuZGluZyA9PSBpbnB1dCR5ZWFyKSAlPiUgCiAgICAgICAgZ3JvdXBfYnkoU1RBQkJSKSAlPiUgbXV0YXRlKGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgPXN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUKICAgICAgICBncm91cF9ieShTVEFCQlIsYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApICU+JSBzdW1tYXJpemUoKX0pCiAgICBsaWJyYXJ5KHRpZ3JpcykKICAgIHN0YXRlcyA8LSBzdGF0ZXMoY2IgPSBUUlVFKQogICAgc3RhdGVzX3llYXIgPC0gcmVhY3RpdmUoe3N0YXRlcyAlPiUgaW5uZXJfam9pbihzY190aW1lX3NlbGVjdGl2ZSgpLCBieT1jKFNUVVNQUz0nU1RBQkJSJykpfSkgCiAgICAKICBvdXRwdXQkc3R1ZGVudGRlYnRtYXAgPC0gcmVuZGVyTGVhZmxldCh7CiAgICBwYWwgPSBjb2xvckZhY3RvcignR3JlZW5zJywgZG9tYWluID0gc3RhdGVzX3llYXIoKSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkKICAgIHBvcF9wb3AgPC0gcGFzdGUoIlN0YXRlOiIsc3RhdGVzX3llYXIoKSROQU1FLCI8YnIvPiIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMiLCI8YnIvPiIsICJvZiBTY2hvb2xzIExvY2F0ZWQgaW4gU3RhdGU6IiwKICAgICAgICAgICAgICAgICAgICAgcGFzdGUoJyQnLHJvdW5kKHN0YXRlc195ZWFyKCkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSkKICAgIAogICAgc2NfdGltZV9zZWxlY3RpdmVfdGl0bGUgPC0gdGFncyRwKHRhZ3Mkc3R5bGUoJ3B7Y29sb3I6Z3JheTsgZm9udC1zaXplOiAxNHB4OyBmYW1pbHk6IHNlcmlmfScpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFncyRiKCdBdmVyYWdlIERlYnQgQnkgU3RhdGUgKDIwMTkpJykpCiAgICBsZWFmbGV0KHN0YXRlc195ZWFyKCkpICU+JSBhZGRQcm92aWRlclRpbGVzKCJDYXJ0b0RCLlBvc2l0cm9uIikgJT4lCiAgICAgIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5wYWwoc3RhdGVzX3llYXIoKSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCksCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMC41LAogICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNywgIAogICAgICAgICAgICAgIGhpZ2hsaWdodCA9IGhpZ2hsaWdodE9wdGlvbnMoCiAgICAgICAgICAgICAgICB3ZWlnaHQgPSA1LAogICAgICAgICAgICAgICAgY29sb3IgPSAiIzY2NiIsCiAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNywKICAgICAgICAgICAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUsCiAgICAgICAgICAgICAgICApLHBvcHVwPXBvcF9wb3ApICU+JSBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tbGVmdCIsIGNvbG9ycyA9YygiI0VERjhFOSIsIiNCQUU0QjMiLCIjNzRDNDc2IiwiIzMxQTM1NCIsIiMwMDZEMkMiKSwgCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMocGFzdGUoJyQnLHJvdW5kKG1pbihzdGF0ZXNfeWVhcigpJGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSkpLCIgIiwiICIsIiAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgnJCcscm91bmQobWF4KHN0YXRlc195ZWFyKCkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSkpLAogICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMgKFBlciBTdHVkZW50KSIpICU+JQogIGxlYWZsZXQ6OnNldFZpZXcoLTk4LjU3OTUsIDM5LjgyODIsIHpvb209MykgJT4lIGFkZENvbnRyb2woc2NfdGltZV9zZWxlY3RpdmVfdGl0bGUsIHBvc2l0aW9uPSd0b3ByaWdodCcpCiAgICB9KQogICAgb2JzZXJ2ZSh7CiAgICBsZWFmbGV0UHJveHkoInN0dWRlbnRkZWJ0bWFwIiwgZGF0YSA9IHN0YXRlc195ZWFyKCkpCiAgfSkgCn0KCnNoaW55QXBwKHVpID0gdWksIHNlcnZlciA9IHNlcnZlcikKCmBgYAoKTm90IGFsbCBzY2hvb2xzIGhhdmUgc2ltaWxhciBhbW91bnRzIG9mIG1lZGlhbiBzdHVkZW50IGRlYnQgYnVyZGVuIChpLmUuLCB1cG9uIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHJlcGF5bWVudCBwZXJpb2QpLiBUaGlzIG1hcCBzdW1tYXJpemVzIHRoZSBtZWRpYW4gZGVidCBidXJkZW4gYnkgdGhlIHN0YXRlIHRoYXQgdGhlIHNjaG9vbCBpcyBsb2NhdGVkIGluLiBBcyBzaG93biBpbiB0aGlzIHBsb3QsIHNvbWUgc3RhdGVzIChpbmNsdWRpbmcgc2Nob29scyBpbiBQZW5uc3lsdmFuaWEsIE1pbm5lc290YSwgSWxsaW5vaXMsIGV0Yy4pIHRlbmQgdG8gaGF2ZSB0aGUgaGlnaGVzdCBhdmVyYWdlIG1lZGlhbiBkZWJ0IGJ1cmRlbiBiZXR3ZWVuIHRoZSBzY2hvb2xzIHdpdGhpbi4gVGhlc2Ugc3RhdGVzIGRvIG5vdCBuZWNlc3NhcmlseSBob3VzZSB0aGUgbW9zdCBwcmVzdGlnaW91cyBzY2hvb2xzLiBPbmUgb2YgdGhlIHRoaW5ncyB3ZSBjYW4gc2VlIHdoZW4gZGlzYWdncmVnYXRpbmcgdGhpcyB3YXkgaXMgdGhhdCBsb2NhdGlvbmFsbHkgdGhlcmUgaXMgYSBsb3Qgb2YgZGl2ZXJzaXR5IG9mIHRoZSBzdHVkZW50IGxvYW4gYnVyZGVuIChvbiBhdmVyYWdlKSBnaXZlbiB0byBzdHVkZW50cyBieSBzY2hvb2xzIHdoZW4gZGlzYWdncmVnYXRlZCBhdCB0aGUgc3RhdGUgbGV2ZWwgKHJhbmdpbmcgZnJvbSA0SyB0byAxOEsgVVNEIGluIDIwMTkpCk5vdGUgdGhhdCB3ZSBoYXZlIGFsc28gaW5jbHVkZWQgdGhlIHNoaW55IGludGVyYWN0aXZpdHkgY29tcG9uZW50IGluIHdoaWNoIG9uZSBjYW4gc2VsZWN0IHRoZSB5ZWFyIG9uIHRoZSBzbGlkZXIgdG8gc2VlIHRoZSBzdGF0ZS1sZXZlbCBkZWJ0IG1lZGlhbiBkaXNhZ2dyZWdhdGlvbiBhY3Jvc3MgdGhlIHllYXJzOyB0aGlzIGlzIG5vdCB0aGUgcHJpbWFyeSBmdW5jdGlvbiBidXQgaW5zdGVhZCBpcyBhIGZ1bmN0aW9uYWxpdHkgd2UgYWRkZWQgdG8gYWxsb3cgaW5kaXZpZHVhbHMgdG8gJ2V4cGxvcmUgdGhlIGRhdGEnIGEgYml0LiAKCmBgYHtyfQp1aSA8LSBmbHVpZFBhZ2UoCiAgdGl0bGVQYW5lbCgnVGhlIENvc3Qgb2YgSGlnaGVyIEVkdWNhdGlvbjogQW4gRXhwbG9yYXRpb24gb2YgU3R1ZGVudCBEZWJ0IGluIEFtZXJpY2FuIFVuaXZlcnNpdGllcycpCiAgCikKIApgYGAKCg==